library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use work.constants.all;

entity sequencer2 is
    port(
		rst                : in  std_logic;
		clk              	 : in  std_logic;
		ale		  	 : out std_logic;
		psen		 	 : out std_logic;

		alu_op_code	 	 : out  std_logic_vector (3 downto 0);
		alu_src_1L		 : out  std_logic_vector (7 downto 0);
		alu_src_1H		 : out  std_logic_vector (7 downto 0);
		alu_src_2L		 : out  std_logic_vector (7 downto 0);
		alu_src_2H		 : out  std_logic_vector (7 downto 0);
		alu_by_wd		 : out  std_logic;             -- byte(0)/word(1) instruction
		alu_cy_bw		 : out  std_logic;             -- carry/borrow bit
		alu_ans_L		 : in std_logic_vector (7 downto 0);
		alu_ans_H		 : in std_logic_vector (7 downto 0);
		alu_cy		 	 : in std_logic;             -- carry out of bit 7/15
		alu_ac		 	 : in std_logic;		    -- carry out of bit 3/7
		alu_ov		 	 : in std_logic;		    -- overflow

		dividend_i		 : out  std_logic_vector(7 downto 0);
		divisor_i		 : out  std_logic_vector(7 downto 0);
		quotient_o		 : in std_logic_vector(7 downto 0); 
		remainder_o	 	 : in std_logic_vector(7 downto 0);
		div_done		 : in std_logic ;

		mul_a_i		 	 : out  std_logic_vector(7 downto 0);  -- Multiplicand
		mul_b_i		 	 : out  std_logic_vector(7 downto 0);  -- Multiplicator
		mul_prod_o 	 	 : in std_logic_vector(15 downto 0) ;-- Product

		i_ram_wrByte   	 : out std_logic; 
		i_ram_wrBit   	 : out std_logic; 
		i_ram_rdByte   	 : out std_logic; 
		i_ram_rdBit   	 : out std_logic; 
		i_ram_addr 	 	 : out std_logic_vector(7 downto 0); 
		i_ram_diByte  	 : out std_logic_vector(7 downto 0); 
		i_ram_diBit   	 : out std_logic; 
		i_ram_doByte   	 : in std_logic_vector(7 downto 0); 
		i_ram_doBit   	 : in std_logic; 
		
		i_rom_addr       : out std_logic_vector (15 downto 0);
		i_rom_data       : in  std_logic_vector (7 downto 0);
		i_rom_rd         : out std_logic;
		
		pc_debug	 	 : out std_logic_vector (15 downto 0);
      Serving_int	 : out  STD_LOGIC_VECTOR (3 downto 0);
      Next_INT 	 : in  STD_LOGIC_VECTOR (3 downto 0);
		erase_flag	 : out std_logic);

end sequencer2;

-------------------------------------------------------------------------------

architecture seq_arch of sequencer2 is

   type t_cpu_state 		is (S1, S2, S3, S4, S5, S6); 	--these determine whether you are in initialisation, state, normal execution state, etc
   type t_exe_state 		is (E0, E1); 						--these are the equivalence T0, T1 in the lecture
    
	signal cpu_state 		: t_cpu_state;
   signal exe_state 		: t_exe_state;
	signal Cycle			: std_logic_vector(1 downto 0);			-- Signal to keep track cycle
   signal IR				: std_logic_vector(7 downto 0);			-- Instruction Register
	signal PC				: std_logic_vector(15 downto 0);			-- Program Counter
	signal AR				: std_logic_vector(7 downto 0);			-- Address Register
	signal DR				: std_logic_vector(7 downto 0);			-- Data Register
	signal int_fetch		: std_logic;

	signal curr_int	:	std_logic_vector(3 Downto 0);
begin

Serving_int <= curr_int;

    process(rst, clk)
    begin
    if( rst = '1' ) then
		cpu_state <= S1;
		exe_state <= E0;
		ale <= '0'; psen <= '0';
		mul_a_i <= (others => '0'); mul_b_i <= (others => '0');
		dividend_i <= (others => '0'); divisor_i <= (others => '1');
		i_ram_wrByte <= '0'; i_ram_rdByte <= '0'; i_ram_wrBit <= '0'; i_ram_rdBit <= '0';
		Cycle <= (others => '0');
		IR <= (others => '0');
		PC <= (others => '0');
		AR <= (others => '0');
		DR <= (others => '0');
		pc_debug <= (others => '1');
		curr_int <= (others => '0');
		int_fetch <= '0';
		erase_flag <= '0';
    elsif (clk'event and clk = '1') then
		case cpu_state is
		
			-- Fetching state
			when S1=>
				case exe_state is
					when E0=>
						
						-- Request instruction from ROM
						i_rom_addr <= PC;
						i_rom_rd <= '1';
						-- Left RAM untouch, reserve for pipelining
						
						--Update to next state
						exe_state <= E1;
						cpu_state <= S1;
					when E1=>
						if( Cycle = Remain_4Cycles ) then
							if( int_fetch = '1' ) then
								IR <= "00010010";	-- LCALL
								-- If we need to vector curr interrupt, Preform a LCALL
								-- Since we pretend there is a LCALL, threfore, not updating PC
							else
								-- No more execution for last instruction, update the IR and PC
								-- become "11", which mean overflow for last instruction, meaning finish instruction
								IR <= i_rom_data;
								PC <= PC + 1;		
							end if;
						end if;
						
						
							--Update to next state
							exe_state <= E0;
							cpu_state <= S2;
					when others =>
						Cycle <= Remain_4Cycles;
						exe_state <= E0;
						cpu_state <= S1;
				end case;
				
			-- Decode + Memory State 1 (Acc & PSW)
			-- Determined how many machine cycle is need for particular instruction
			-- Note that no ROM access is allowed in current section
			when S2=>
				case exe_state is
					when E0=>
						--===================== DECODE SECTION ===================================
						-- Decode the new instruction, Update the Machinese cycle required to DR
						if( Cycle = Remain_4Cycles ) then
							case IR is
								-- 2 machine cycles instructions, count 1 time before overflow
								when 	"10100011"| 	-- INC DPTR, 2 machine cycles
										"00010010"|		-- LCALL
										"00100010"|		-- RET
										"00110010"|		-- RETI
										"00010001"|"00110001"|"01010001"|"01110001"|"10010001"|"10110001"|"11010001"|"11110001"|		-- ACALL addr11
										"00000001"|"00100001"|"01000001"|"01100001"|"10000001"|"10100001"|"11000001"|"11100001"|		-- AJMP addr11
										"01010011"|			-- ANL direct,#data
										"01000011"|			--ORL direct,#data
										"01100011"|			--XRL direct,#data
										"10000010"|			-- ANL C,bit
										"01110010"|			--ORL C,bit
										"10110000"|			--ANL C./bit
										"10100000"|			--ORL C,/bit
										"10010010"|			--mov bit,c
										"01000000"|  		--JC rel
										"01010000"|			--JNC rel
										"00100000"|			--JB bit,rel
										"00110000"|       --JNB bit,rel
										"00010000"|			--JBC bit rel
										"01110000"|			--JNZ
										"01100000"|			--JZ
										"00000010"|       --LJMP
										"10000000"|			--SJMP
										"10110101"|			--CJNE A,direct,rel
										"10110100"|			-- CJNE A,#data,rel
										"10111000" | "10111001" |"10111010" |"10111011"|"10111100"| "10111101"|"10111110"|"10111111"|	 --CJNE Rn,#data,rel
										"10110110" |"10110111"|	--CJNE @Rn,#data,rel
										"10000110" | "10000111"|	-- MOV Direct, @Ri
										"10101000" | "10101001" | "10101010" | "10101011" | "10101100" | "10101101" | "10101110" |"10101111"| -- Mov Rn,direct
										"10001000"|"10001001"|"10001010"|"10001011"|"10001100"|"10001101"|"10001110"|"10001111"| --Mov direct,Rn
										"01110101"|  -- MOV direct,#data
										"10000101"| -- MOV direct,direct 
										"11011000"| "11011001"|"11011010"|"11011011"|"11011100"|"11011101"|"11011110"|"11011111"|  --DJNZ Rn,rel
										"11010101"| --DJNZ direct,rel
										"11000000"|	-- PUSH
										"11010000"|	--	POP
										"01110011"|  --JMP DPTR
										"10010000"|	-- MOV DPTR, #data_16
										"10010011"|	-- MOV A, @(A+DPTR)
										"10000011"|	-- MOV A, @(A+PC)
										"10100110"|"10100111" --Mov @Ri, direct
										=> Cycle <= Remain_2Cycles;
									
								-- 3 machine cycles instructions, count 2 time before overflow.
									
								-- 4 machine cycles instructions, count 3 time before overflow.
								when 	"10000100"|		-- DIV AB, 4 machine cycles
										"10100100"		-- MUL AB, 4 machine cycles
									=> Cycle <= Remain_4Cycles;
									
								-- Normal instructions, just 1 cycle
								when others 
									=>	Cycle <= Remain_1Cycles;
							end case;
						end if;
						--========================================================================
						
						-- Reset the Erase flag for next interrupt
						erase_flag <= '0';
						-- Read Acc & PSW in advance.
						i_ram_wrByte <= '0'; 
						i_ram_rdByte <= '1'; 
						i_ram_wrBit <= '0'; 
						i_ram_rdBit <= '0';
						i_ram_addr <= Acc; 				-- Load ACC to BUS
						
							--Update to next state
							exe_state <= E1;
							cpu_state <= S2;
					when E1=>
						-- put Acc to the DR first
						case IR is
							when 	"00010010"|		-- LCALL
									"00100010"|		-- RET
									"00110010"|		-- RETI
									"01010011"|			-- ANL direct,#data
									"01000011"|			--ORL direct,#data
									"01100011"| 			--XRL direct,#data
									"10000010"|			-- ANL C,bit
									"01110010"|			--ORL C,bit
									"00100000"|			--JB bit,rel
									"00110000"|       --JNB bit,rel
									"00010000"|			--JBC bit rel
									"00000010"|        --LJMP
									"10111000" | "10111001" |"10111010" |"10111011"|"10111100"| "10111101"|"10111110"|"10111111"|	 --CJNE Rn,#data,rel
									"10110110" |"10110111"|	--CJNE @Rn,#data,rel
									"10000110" | "10000111"|	-- MOV Direct, @Ri
									"01110101" | -- MOV direct,#data
									"10001000"|"10001001"|"10001010"|"10001011"|"10001100"|"10001101"|"10001110"|"10001111"| --Mov direct,Rn
									"10101000" | "10101001" | "10101010" | "10101011" | "10101100" | "10101101" | "10101110" |"10101111"| -- Mov Rn,direct
									--********Lin******----------
									"10100010"|	-- MOV C, bit
									"10010010"|	-- MOV bit, C
									"11011000"|"11011001"|"11011010"|"11011011"|"11011100"|"11011101"|"11011110"|"11011111"|  --DJNZ Rn,rel
									"11010101"| --DJNZ direct,rel
									"00010001"|"00110001"|"01010001"|"01110001"|"10010001"|"10110001"|"11010001"|"11110001"|		-- ACALL addr11
									"00000001"|"00100001"|"01000001"|"01100001"|"10000001"|"10100001"|"11000001"|"11100001"|		-- AJMP addr11
									"11000000"|	-- PUSH
									"11010000"|	--	POP
									"10010000"|	-- MOV DPTR, #data_16
									"10000101"| -- MOV direct,direct 
									"10100110"|"10100111" --Mov @Ri, direct
									=> -- Do nothing, just by pass the updating DR
							when "01110000"|			--JNZ
								"01100000"			--JZ
								=>AR<=i_ram_doByte;
							when "10110101"|			--CJNE A,direct,rel
								"10110100"			-- CJNE A,#data,rel
								=> 
								if(Cycle=Remain_1Cycles) then
									AR <=i_ram_doByte;
								elsif(Cycle=Remain_2Cycles) then
									DR <= i_ram_doByte;
								end if;
							when 	others
									=> DR <= i_ram_doByte;
						end case;
					
						i_ram_wrByte <= '0'; 
						i_ram_rdByte <= '1'; 
						i_ram_wrBit <= '0'; 
						i_ram_rdBit <= '0';
						i_ram_addr <= PSW; 				-- Load PSW to BUS
						-- So the PSW will on the bus now, until next reading
						
							--Update to next state
							exe_state <= E0;
							cpu_state <= S3;
					when others =>
						Cycle <= Remain_4Cycles;
						exe_state <= E0;
						cpu_state <= S1;
				end case;
				
			-- Memory State 2 (RAM)
			-- Reading required data from RAM memory
			when S3=>
				case exe_state is
					when E0=>
						-- Backup PSW
						case IR is
							when 	"00010010"|		-- LCALL
									"00100010"|		-- RET
									"00110010"|		-- RETI
									"01010011"|			-- ANL direct,#data
									"01000011"|			--ORL direct,#data
									"01100011"| 			--XRL direct,#data
									"00100000"|			--JB bit,rel
									"00110000"|       --JNB bit,rel
									"00010000"|			--JBC bit rel
									"01110000"|			--JNZ
									"01100000"|			--JZ
									"10000101"| -- MOV direct,direct 
									"01110101" | -- MOV direct,#data
									"00000010" |     --LJMP
									"11010101"| --DJNZ direct,rel
									"00000001"|"00100001"|"01000001"|"01100001"|"10000001"|"10100001"|"11000001"|"11100001"|		-- AJMP addr11
									"00010001"|"00110001"|"01010001"|"01110001"|"10010001"|"10110001"|"11010001"|"11110001"|		-- ACALL addr11
									"11000000"|	-- PUSH
									"11010000"|	--	POP
									"10010000"|	-- MOV DPTR, #data_16
									"10010011"|	-- MOV A, @(A+DPTR)
									"10000011"	-- MOV A, @(A+PC)
									=> -- Do nothing, just by pass the updating AR
							when 	"10110101"|  --CJNE A,direct,rel
									"10110100"|			-- CJNE A,#data,rel
									"10111000" | "10111001" |"10111010" |"10111011"|"10111100"| "10111101"|"10111110"|"10111111"|	 --CJNE Rn,#data,rel
									"10110110" |"10110111"	--CJNE @Rn,#data,rel
									
									=>
									if(Cycle =Remain_2Cycles) then
										AR <=i_ram_doByte;
									end if;
							when "10101000" | "10101001" | "10101010" | "10101011" | "10101100" | "10101101" | "10101110" |"10101111"-- Mov Rn,direct
								
									=>
									if(Cycle =Remain_1Cycles) then
										AR <=i_ram_doByte;
									end if;
							when	others
									=>AR <= i_ram_doByte;
						end case;
						
						-- Read memory according to the natural of the instruction
						case IR is
							when 	"00101000"| "00101001"| "00101010"| "00101011"| "00101100"| "00101101"| "00101110"| "00101111"|		-- ADD Acc, Rn
									"00111000"| "00111001"| "00111010"| "00111011"| "00111100"| "00111101"| "00111110"| "00111111"|  	-- ADDC Acc, Rn
									"10011000"| "10011001"| "10011010"| "10011011"| "10011100"| "10011101"| "10011110"| "10011111"|  	-- SBBC Acc, Rn
									"00011000"| "00011001"| "00011010"| "00011011"| "00011100"| "00011101"| "00011110"| "00011111"|		-- DEC Rn
									"00001000"| "00001001"| "00001010"| "00001011"| "00001100"| "00001101"| "00001110"| "00001111"|		-- INC Rn
									"01011000"| "01011001"| "01011010"| "01011011"| "01011100"| "01011101" | "01011110"| "01011111"|	 --ANL Acc,Rn
									"01001000" | "01001001" | "01001010" | "01001011" | "01001100" | "01001101" | "01001110" | "01001111"| --ORL Acc,Rn
									"01101000" | "01101001" | "01101010" | "01101011" | "01101100" | "01101101" | "01101110" | "01101111"|--XRL ACC,Rn
									"11101000"|"11101001"|"11101010"|"11101011"|"11101100"|"11101101"|"11101110"|"11101111" 		-- Mov A, Rn
									
									=>
									
									-- Read Rn from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load Rn to BUS
									i_ram_addr <= "000" & i_ram_doByte(4 DOWNTO 3) & IR(2 DOWNTO 0);
							
							when 	"11001000"|"11001001"|"11001010"|"11001011"|"11001100"|"11001101"|"11001110"|"11001111"		-- XCH A,Rn
									=>
									-- Read Rn from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load Rn to BUS
									i_ram_addr <= "000" & i_ram_doByte(4 DOWNTO 3) & IR(2 DOWNTO 0);
							
									AR <= "000" & i_ram_doByte(4 DOWNTO 3) & IR(2 DOWNTO 0);
									
							when	"10111000" | "10111001" |"10111010" |"10111011"|"10111100"| "10111101"|"10111110"|"10111111"|	 --CJNE ACC,Rn,rel
									"10001000"|"10001001"|"10001010"|"10001011"|"10001100"|"10001101"|"10001110"|"10001111"| --Mov direct,Rn
									"11011000"|"11011001"|"11011010"|"11011011"|"11011100"|"11011101"|"11011110"|"11011111"  --DJNZ Rn,rel
									=>
									if(Cycle=Remain_2Cycles) then
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load Rn to BUS
									i_ram_addr <= "000" & i_ram_doByte(4 DOWNTO 3) & IR(2 DOWNTO 0);
									end if;							
									-- not implementation for next cycle, because the data is already on the bus
									
							when	"11111000" | "11111001" | "11111010" | "11111011" | "11111100" | "11111101" | "11111110" | "11111111"| --Mov Rn,A
									"11110101"|			--Mov direct,A
									"11110110" | "11110111"	--MOV @Ri,A
									=>
									-- Read Acc from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load A to BUS
									i_ram_addr <= Acc;
							when 	"00100110"|"00100111"|			-- ADD A,@Ri
									"00110110"|"00110111"|			-- ADDC A,@Ri
									"10010110"|"10010111"|			-- SUBB A,@Ri
									"00010110"|"00010111"|		-- DEC @Ri
									"00000110"|"00000111"|		-- INC @Ri
									"01010110"| "01010111"|		-- ANL A,@Ri
									"01000110" | "01000111"|	--ORL A,@Ri
									"01100110" | "01100111"| 	--XRL A,@Ri
									"11100110"|"11100111"|			-- MOV A,@Ri
									"01110110" | "01110111"|  --MOV @Ri,#data
									"10000110" | "10000111"|	-- MOV Direct, @Ri
									"11000110" | "11000111"|	-- XCH A, @Ri
									"11010110" | "11010111"		-- XCHD A, @Ri
									=>
									
									-- Read (Ri) from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load (Ri) to BUS
									i_ram_addr <= "000" & i_ram_doByte(4 DOWNTO 3) & "00" & IR(0);

							when 	"10010011"	-- MOV A, @(A+DPTR)	
									=>
									if(Cycle=Remain_2Cycles) then
										-- Read (Ri) from RAM
										i_ram_wrByte <= '0'; 
										i_ram_rdByte <= '1'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';				-- Load (Ri) to BUS
										i_ram_addr <= DPH;
									end if;
									
							when "10110110" |"10110111"|	--CJNE @Ri,#data,rel
								"10100110"|"10100111" --Mov @Ri, direct
								=>
								if(Cycle=Remain_2Cycles) then
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load Ri to BUS
									i_ram_addr <= "000" & i_ram_doByte(4 DOWNTO 3) & "00" & IR(0);
									end if;
							when 	"10100011"|		-- INC DPTR
									"01110011"  --JMP DPTR
									=>
									-- Read DPL from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load DPL to BUS
									i_ram_addr <= DPL;
									
							when 	"10100100"|		-- MUL AB	
									"10000100"		-- DIV AB
									=>
									-- Read B from Registers File
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load B to BUS
									i_ram_addr <= B;
							
							when 	"00010010"|		-- LCALL
									"00000001"|"00100001"|"01000001"|"01100001"|"10000001"|"10100001"|"11000001"|"11100001"|		-- AJMP addr11
									"00010001"|"00110001"|"01010001"|"01110001"|"10010001"|"10110001"|"11010001"|"11110001"|		-- ACALL addr11
									"11000000"	-- PUSH
									=>		
									if( Cycle = Remain_2Cycles ) then
										-- Read Rn from RAM
										i_ram_wrByte <= '0'; 
										i_ram_rdByte <= '1'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';				-- Load SP to BUS
										i_ram_addr <= SP;		
									end if;
							when	"11010000"	--	POP
									=>
									if( Cycle = Remain_1Cycles ) then
										-- Read Rn from RAM
										i_ram_wrByte <= '0'; 
										i_ram_rdByte <= '1'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';				-- Load SP to BUS
										i_ram_addr <= SP;		
									end if;
									
							when	"00110010"|		-- RETI
									"00100010"		-- RET
									=>		
									if( Cycle = Remain_2Cycles ) then
										-- Read SP from RAM
										i_ram_wrByte <= '0'; 
										i_ram_rdByte <= '1'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';				-- Load SP to BUS
										i_ram_addr <= SP;	
									else
										-- Read new PC from RAM
										i_ram_wrByte <= '0'; 
										i_ram_rdByte <= '1'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';				-- Load (SP) to BUS
										i_ram_addr <= AR + 1;	
									end if;
							when 	others
									=>
								-- No defined, just do nothing
						end case;
							--Update to next state
							exe_state <= E1;
							cpu_state <= S3;
					when E1=>
						case IR is	
							-- If the instruction finish loading data from RAM already, just leave this sub-state do nothing
							-- To save some comparison gates.
							when 	"00100110"|"00100111"|			-- ADD A,@Ri
									"00110110"|"00110111"|			-- ADDC A,@Ri
									"10010110"|"10010111"|			-- SUBB A,@Ri
									"01010110"| "01010111"|		-- ANL A,@Ri
									"01000110" | "01000111"|	--ORL A,@Ri
									"01100110" | "01100111"| 	--XRL A,@Ri
									"11100110"|"11100111"			-- MOV A,@Ri
									=>
									
									-- Read @Ri from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load @Ri to BUS
									i_ram_addr <= i_ram_doByte;
									
							when 	"11000110" | "11000111"|	-- XCH A, @Ri
									"11010110" | "11010111"		-- XCHD A, @Ri
									=>
									AR <= i_ram_doByte;
									
									-- Read @Ri from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load @Ri to BUS
									i_ram_addr <= i_ram_doByte;
									
							when 	"11111000" | "11111001" | "11111010" | "11111011" | "11111100" | "11111101" | "11111110" | "11111111"| --Mov Rn,A
									"11110101"|			--Mov direct,A
									"11110110" | "11110111"	--MOV @Ri,A
							
									=>
									DR <= i_ram_doByte;	
							when  "10110110" |"10110111"|	--CJNE @Ri,#data,rel
								"10100110"|"10100111" --Mov @Ri, direct
							=>
							if(Cycle=Remain_2Cycles) then
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load @Ri to BUS
									i_ram_addr <= i_ram_doByte;
							end if;
							
							when	"01110110" | "01110111"  --MOV @Ri,#data
									=>
									AR <= i_ram_doByte;
									
							when 	"10010011"	-- MOV A, @(A+DPTR)	
									=>
									if(Cycle=Remain_2Cycles) then
										-- AR is containing DPH, DR is containing Acc
										AR <= i_ram_doByte;
										
										-- Read (Ri) from RAM
										i_ram_wrByte <= '0'; 
										i_ram_rdByte <= '1'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';				-- Load (Ri) to BUS
										i_ram_addr <= DPL;
									end if;	
									
							when 	"00010110"|"00010111"|		-- DEC @Ri
									"00000110"|"00000111"		-- INC @Ri
									=>
									
									-- Read @Ri from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load @Ri to BUS
									i_ram_addr <= i_ram_doByte;
									
									AR <= i_ram_doByte;				-- Update AR to share code for Write back state(S6)
									
							when 	"10100011"| 		-- INC DPTR
									"01110011"  --JMP DPTR
									=>
									-- Read DPH from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load DPH to BUS
									i_ram_addr <= DPH;
									
									AR <= i_ram_doByte;				-- Backup DPL into AR
							
							when 	"00010010"|		-- LCALL
									"00000001"|"00100001"|"01000001"|"01100001"|"10000001"|"10100001"|"11000001"|"11100001"|		-- AJMP addr11
									"00010001"|"00110001"|"01010001"|"01110001"|"10010001"|"10110001"|"11010001"|"11110001"|		-- ACALL addr11
									"11000000"	-- PUSH
									=>		
									if( Cycle = Remain_2Cycles ) then
										-- Store SP+1 into AR
										AR <= i_ram_doByte + 1;
									end if;
									
							when	"11010000"	--	POP
									=>
									if( Cycle = Remain_1Cycles ) then
										i_ram_wrByte <= '0'; 
										i_ram_rdByte <= '1'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
										i_ram_addr <= i_ram_doByte;
										-- Store (SP) into bus
										DR	<= i_ram_doByte;
										
									end if;
							when	"00110010"|		-- RETI
									"00100010"		-- RET
									=>
									if( Cycle = Remain_2Cycles ) then
										-- Store SP-1 into AR
										AR <= i_ram_doByte - 1;
									else
										PC(15 Downto 8) <= i_ram_doByte;
										-- Read new PC from RAM
										i_ram_wrByte <= '0'; 
										i_ram_rdByte <= '1'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';				-- Load (SP - 1) to BUS
										i_ram_addr <= AR;
									end if;
							when 	"10000110" | "10000111"	-- MOV Direct, @Ri
									=>
									-- Read @Ri from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Load @Ri to BUS
									i_ram_addr <= i_ram_doByte;
							when 	others 
									=> 
						end case;
						
							--Update to next state
							exe_state <= E0;
							cpu_state <= S4;
					when others =>
						Cycle <= Remain_4Cycles;
						exe_state <= E0;
						cpu_state <= S1;
				end case;
				
			-- Memory State 4 (ROM)
			-- Reading required data from ROM memory
			when S4=>
				case exe_state is
					when E0=>
						
							-- Request information from ROM
							case IR is
							when 	"10010011"|	-- MOV A, @(A+DPTR)
									"10000011"	-- MOV A, @(A+PC)
									=>
									if( Cycle = Remain_1Cycles) then
										i_rom_addr <= alu_ans_H & alu_ans_L;
									end if;
							when 	others	=>
									i_rom_addr <= PC;
								-- Left RAM untouch, reserve for pipelining
							end case;
							i_rom_rd <= '1';
							
							--Update to next state
							exe_state <= E1;
							cpu_state <= S4;
					when E1=>
						case IR is
							when 	"10010000"	-- MOV DPTR, #data_16
									=>
									PC <= PC + 1;
									if(Cycle = Remain_2Cycles) then
										AR <= i_rom_data; 		-- Load direct to BUS
									else
										DR <= i_rom_data; 		-- Load direct to BUS
									end if;
							when 	"00100100"|		-- ADD A,#data
									"00110100"|		-- ADDC A,#data
									"10010100"|		-- SUBB A, #data
									"01100100"|		--XRL A,#data
									"01000100"|		--ORL A,#data
									"01010100"|		--ANL A,#data
									"10111000" | "10111001" |"10111010" |"10111011"|"10111100"| "10111101"|"10111110"|"10111111"| --CJNE ACC,Rn,rel
									"10110110" |"10110111"|	--CJNE @Rn,#data,rel
									"01110100"|		--  MOV A,#data
									"01111000" |"01111001" |"01111010" |"01111011" |"01111100" |"01111101" |"01111110" |"01111111"| --MOV Rn,#data 
									"01110110" | "01110111"  --MOV @Ri,#data
									=>
									-- Left the #data/direct address on the BUS
									PC <= PC + 1;
							
							when 	"11000101"		-- XCH A, direct
									=>
									PC <= PC + 1;
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= i_rom_data; 		-- Load direct to BUS
									
									AR <= i_rom_data;
									
							when  "10101000" | "10101001" | "10101010" | "10101011" | "10101100" | "10101101" | "10101110" |"10101111"| -- Mov Rn,direct
									"11000000"	-- PUSH
									=>
									if(Cycle = Remain_2Cycles)then
										PC <= PC + 1;
										i_ram_wrByte <= '0'; 
										i_ram_rdByte <= '1'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
										i_ram_addr <= i_rom_data; 		-- Load direct to BUS
									end if;
							when 	"11010000"	--POP
									=>
									if(Cycle = Remain_2Cycles)then
										PC <= PC + 1;
										AR <= i_rom_data; 		-- Backup Direct to AR
									end if;
							when 	"00100101"|		-- ADD A,direct
									"00110101"|		-- ADDC A,direct
									"10010101"|		-- SUBB A,direct
									"00010101"|		-- DEC direct
									"00000101"|		-- INC direct
									"11100101"|	 	-- Mov A,direct
									"01010101"| 		--ANL A,direct
									"01000101"|			--ORL A,direct
									"01100101"|		--XRL a,direct
									"01010010"|		--ANL direct,A
									"01000010"|		--ORL direct A
									"01100010"|		--XRL direct A
									"11110101"			--Mov direct,A
									
									=>
									-- Left the #data/direct address on the BUS
									PC <= PC + 1;
									
									-- Read (direct) from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= i_rom_data; 		-- Load direct to BUS
							when "10110101"|			--CJNE A,direct,rel
								"10110100"			-- CJNE A,#data,rel
									=>
									PC <= PC +1;
									if(Cycle=Remain_2Cycles) then
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= i_rom_data; 	
									end if;
							when "11011000"|"11011001"|"11011010"|"11011011"|"11011100"|"11011101"|"11011110"|"11011111"  --DJNZ Rn,rel
						=>
								if(Cycle=Remain_1Cycles) then
									PC <=PC+1;
								end if;
						when 		"01010011"|			-- ANL direct,#data
									"01000011"|			--ORL direct,#data
									"01100011"| 			--XRL direct,#data
									"11010101" --DJNZ direct,rel
								=>
								PC <= PC+1;
								if(Cycle=Remain_2Cycles) then
								i_ram_addr <= i_rom_data;
								AR<= i_rom_data;
								end if;
							when "01110101"  -- MOV direct,#dat
									=>
									if(Cycle = Remain_2Cycles )then
										PC <= PC + 1;
										AR  <= i_rom_data;		--First retrieve direct value and store in Address Registe
									elsif(Cycle = Remain_1Cycles )then
										PC <= PC + 1;
										DR<= i_rom_data; 		-- Then retrive #data for assign
									end if;
									
						when  "11110110" | "11110111"	--MOV @Ri,A
									=>
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';	
									i_ram_addr <= "000" & AR(4 DOWNTO 3) & "00" & IR(0);
							
							when 	"10100010"		--MOV c,bit
									=>
											PC <= PC + 1;
											i_ram_wrByte <= '0'; 
											i_ram_rdByte <= '0'; 
											i_ram_wrBit <= '0'; 
											i_ram_rdBit <= '1';
											i_ram_addr <= i_rom_data; 		-- Load direct to BUS
							
							when  "10010010"		--MOB bit,c
									=>
										if( Cycle = Remain_1CycleS ) then 
											PC <= PC + 1;
										end if;
										
							when "10000101"  -- MOV direct,direct 
									=>
									if(Cycle = Remain_2Cycles)then
									PC<=PC+1;
									
--									 Read (direct) from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= i_rom_data; 		-- Load direct to BUS
									elsif(Cycle = Remain_1Cycles )then
									PC <= PC + 1;
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= i_rom_data; 		-- Load direct to BUS
									AR <= i_rom_data;
									
									end if;			
							
						when  "11000010" |  --CLR bit
								"11010010"|	--set B
								"10110010"|	-- CPL bit
								"10000010"|			-- ANL C,bit
								"01110010"|			--ORL C,bit
								"10110000"|			--ANL C./bit
								"10100000"			--ORL C,/bit		
								
						=>
						if(Cycle=Remain_1Cycles) then
									PC <= PC+1;
										-- Read (direct) from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '1';
									i_ram_addr <= i_rom_data; 		-- Load direct to BUS
									end if;
						when "10100110"|"10100111" --Mov @Ri, direct
							=>
						if(Cycle=Remain_1Cycles) then
									PC <= PC+1;
										-- Read (direct) from RAM
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '1'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= i_rom_data; 		-- Load direct to BUS
									end if;
						when 	"01000000"|  		--JC rel
								"01010000"|			--JNC rel
								"01110000"|			--JNZ
								"01100000"|			--JZ
								"10000000"			--SJMP
								=>
							if(Cycle=Remain_1Cycles) then 
								PC <= PC+1;
								DR<= i_rom_data;
								end if;
						when "00100000"|			--JB bit,rel
								"00110000"|       --JNB bit,rel
								"00010000"			--JBC bit rel
								=>
								PC <= PC+1;
								if(Cycle=Remain_2Cycles) then
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '1';
								i_ram_addr <= i_rom_data;
									AR <=i_rom_data;
								end if;
						when "00000010"        --LJMP
						=>
							PC <= PC+1;
							if(Cycle=Remain_2Cycles) then
									AR <=i_rom_data;
							elsif(Cycle = Remain_1Cycles) then
									DR <=i_rom_data;
								end if;
								
							when 	"00010010"		-- LCALL
									=>
									if( int_fetch = '1') then			
									else
										-- if not hardware generated LCALL, update the PC
										PC <= PC + 1;

									end if;
									
									if( Cycle = Remain_2Cycles ) then
										DR <= i_rom_data;
									-- else if  Remain_1Cycle, we leave it on the bus, later we use it dirrectly
									end if;
							
							when 	"10000110" | "10000111"|	-- MOV Direct, @Ri
									"10001000"|"10001001"|"10001010"|"10001011"|"10001100"|"10001101"|"10001110"|"10001111" --Mov direct,Rn
									=>
									if( Cycle = Remain_1Cycles) then
										PC <= PC + 1;
										AR <=i_rom_data;

									end if;
							when "00000001"|"00100001"|"01000001"|"01100001"|"10000001"|"10100001"|"11000001"|"11100001"|		-- AJMP addr11
									"00010001"|"00110001"|"01010001"|"01110001"|"10010001"|"10110001"|"11010001"|"11110001"		-- ACALL addr11
									=>

									if( Cycle = Remain_2Cycles ) then
										PC <= PC + 1;
										DR <= i_rom_data;

									end if;
							
							when 	others
									=>
									-- If no need to read from ROM,
									-- Ignore the read information
						end case;
						
							--Update to next state
							exe_state <= E0;
							cpu_state <= S5;
					when others =>
						Cycle <= Remain_4Cycles;
						exe_state <= E0;
						cpu_state <= S1;
				end case;
			
			-- Execution State
			-- Execute the current Instruction, apply logic
			when S5=>
				case exe_state is
					when E0=>
						case IR is										
							when "10000101"  -- MOV direct,direct 
									=>
									if(Cycle=Remain_2Cycles) then
										DR <= i_ram_doByte;
									end if;
							when  "01111000" |"01111001" |"01111010" |"01111011" |"01111100" |"01111101" |"01111110" |"01111111" --MOV Rn,#data 
									=>
									DR<=i_rom_data;
									AR <= "000" & AR(4 downto 3) & IR(2 DOWNTO 0);	
									i_ram_addr <= AR; 				-- Write computed result back to Destination
									
								
							when 	"11111000" | "11111001" | "11111010" | "11111011" | "11111100" | "11111101" | "11111110" | "11111111"| --Mov Rn,A
									"00011000"| "00011001"| "00011010"| "00011011"| "00011100"| "00011101"| "00011110"| "00011111"|		-- DEC Rn
									"00001000"| "00001001"| "00001010"| "00001011"| "00001100"| "00001101"| "00001110"| "00001111"		-- INC Rn
									=>
									
									DR <= i_ram_doByte;				-- Update to DR so we can share same logic during Execution.
									AR <= "000" & AR(4 DOWNTO 3) & IR(2 DOWNTO 0); -- Set destination to the Rn
							when "11011000"|"11011001"|"11011010"|"11011011"|"11011100"|"11011101"|"11011110"|"11011111"  --DJNZ Rn,rel
									=>
									if(Cycle=Remain_2Cycles) then
									DR <= i_ram_doByte;				-- Update to DR so we can share same logic during Execution.
									AR <= "000" & AR(4 DOWNTO 3) & IR(2 DOWNTO 0); -- Set destination to the Rn
									--elsif(Cycle=Remain_1Cycles)
									
									end if;		
							when "11100101" | 	-- Mov A,direct
								  "11100110" | "11100111"			-- MOV A,@Ri
									=>
									DR <= i_ram_doByte;				-- Update to DR so we can share same logic during Execution.
									
							when 	"00010101"|		-- DEC direct
									"00000101"		-- INC direct
									=>
									DR <= i_ram_doByte;				-- Update to DR so we can share same logic during Execution.
									AR <= i_rom_data; 				-- Set destination to the Rn
						when 	"01010010"|		--ANL direct,A
									"01000010"|		--ORL direct A
									"01100010"|		--XRL direct A
									"11000010"|	-- CLR bit
									"11010010"|	--set bit
									"10110010"| --CPL bit
									"11110101" 		--Mov direct,A
									=>
									AR <= i_rom_data;						
							when 	"01010011"|			-- ANL direct,#data
									"01000011"|			--ORL direct,#data
									"01100011"|			--XRL direct,#data 
									"10000110" | "10000111"|	-- MOV Direct, @Ri
									"10001000"|"10001001"|"10001010"|"10001011"|"10001100"|"10001101"|"10001110"|"10001111"| --Mov direct,Rn
									"11010101"| --DJNZ direct,rel
									"11000000"	-- PUSH
									=>
									if(Cycle = Remain_2Cycles) then
										DR <= i_ram_doByte;	
									end if;
							when  "10101000" | "10101001" | "10101010" | "10101011" | "10101100" | "10101101" | "10101110" |"10101111" -- Mov Rn,direct
									=>
									if(Cycle = Remain_2Cycles) then
										DR <= i_ram_doByte;
									elsif(Cycle = Remain_1Cycles) then
										AR <= "000" & AR(4 DOWNTO 3) & IR(2 DOWNTO 0); -- Set destination to the Rn
									end if;
							
						 	when "10110101"			--CJNE A,direct,rel
								
								=>
									if(Cycle = Remain_2Cycles) then
									if(DR < i_ram_doByte) then
										AR(7) <='1';
									else
										AR(7) <='0';
										end if;
									DR <= i_ram_doByte;
									end if;
							when "10110100"			-- CJNE A,#data,rel
							=>
								if(Cycle = Remain_2Cycles) then
									if(DR < i_rom_data) then
										AR(7) <='1';
									else
										AR(7) <='0';
										end if;
									DR <= i_rom_data;
									end if;
							when "10111000" | "10111001" |"10111010" |"10111011"|"10111100"| "10111101"|"10111110"|"10111111"|	 --CJNE Rn,#data,rel
							"10110110" |"10110111"	--CJNE @Rn,#data,rel
							=>
							if(Cycle = Remain_2Cycles) then
									if(i_ram_doByte < i_rom_data) then
										AR(7) <='1';
									else
										AR(7) <='0';
										end if;
									DR <= i_rom_data;
									end if;
							when 	"10100110"|"10100111" --Mov @Ri, direct	
							=>
							if(Cycle = Remain_2Cycles) then  --load @Ri to DR;
							DR <=i_ram_doByte;
							end if;
							when	"00010110"|"00010111"|		-- DEC @Ri
									"00000110"|"00000111"		-- INC @Ri
									=>
									DR <= i_ram_doByte;
									
							when 	"11010100"		-- DA A
									=>
									-- Put the Acc into the ALU first
									alu_src_1L <= DR;
									alu_src_1H <= "00000000";
										
									-- Put the +6/+0 into the ALU
									if( DR(3 downto 0) > "1001" or AR(6) = '1' ) then
										alu_src_2L <= "00000110";
										alu_src_2H <= "00000000";
									else
										alu_src_2L <= "00000000";
										alu_src_2H <= "00000000";
									end if;
										
									alu_by_wd <= '0';					-- Calculate only 1 byte
									alu_cy_bw 	<= '0';
									alu_op_code <= ALU_OPC_ADD;
							when  "11110110" | "11110111"	--MOV @Ri,A
									=>
									AR<=i_ram_doByte;
									
							when "01110110" | "01110111"  --MOV @Ri,#data
									=>
									DR <= i_rom_data;
									
							when 	"11101000"|"11101001"|"11101010"|"11101011"|"11101100"|"11101101"|"11101110"|"11101111"		-- Mov A, Rn
									=> 
									DR <= i_ram_doByte;
									AR <= ACC;
							when others
							=>
								-- No defined, just do nothing
						end case;
							--Update to next state
							exe_state <= E1;
							cpu_state <= S5;
					when E1=>
						--============================= INTERRUPT CHECKING ====================================
						if( Cycle = Remain_1Cycles ) then
							if(next_int > curr_int) then
								curr_int <= next_int;
								int_fetch <= '1';
							end if;
						end if;
						--=====================================================================================
					
						case IR is
							when 	"00101000"| "00101001"| "00101010"| "00101011"| "00101100"| "00101101"| "00101110"| "00101111"|		-- ADD Acc, Rn
									"00111000"| "00111001"| "00111010"| "00111011"| "00111100"| "00111101"| "00111110"| "00111111"|  	-- ADDC Acc, Rn
									"10011000"| "10011001"| "10011010"| "10011011"| "10011100"| "10011101"| "10011110"| "10011111"|  	-- SBBC Acc, Rn
									"00100101"|		-- ADD A,direct
									"00110101"|		-- ADDC A,direct
									"10010101"|		-- SUBB A,direct
									"01010101"| 		--ANL A,direct
									"01000101"|			--ORL A,direct
									"01100101"|			--XRL a,direct
									"00100110"|"00100111"|			-- ADD A,@Ri
									"00110110"|"00110111"|			-- ADDC A,@Ri
									"10010110"|"10010111"|			-- SUBB A,@Ri
									"01010110"| "01010111"|		-- ANL A,@Ri
									"01000110" | "01000111"|	--ORL A,@Ri
									"01100110" | "01100111"| 	--XRL A,@Ri
									"00000100"|		-- INC A
									"00010100"|		-- DEC A
									"00011000"| "00011001"| "00011010"| "00011011"| "00011100"| "00011101"| "00011110"| "00011111"|		-- DEC Rn
									"00001000"| "00001001"| "00001010"| "00001011"| "00001100"| "00001101"| "00001110"| "00001111"|		-- INC Rn
									"00010101"|		-- DEC direct
									"00000101"|		-- INC direct
									"00010110"|"00010111"|		-- DEC @Ri
									"00000110"|"00000111"|		-- INC @Ri
									"01011000"| "01011001"| "01011010"| "01011011"| "01011100"| "01011101"| "01011110"| "01011111"| --AND Acc,Rn
									"01001000" | "01001001" | "01001010" | "01001011" | "01001100" | "01001101" | "01001110" | "01001111"| --ORL Acc,Rn
									"01101000" | "01101001" | "01101010" | "01101011" | "01101100" | "01101101" | "01101110" | "01101111"|  --XRL,Acc,Rn
									"01010010"|		--ANL direct,A
									"01000010"|		--ORL direct A
									"01100010"		--XRL direct A
									=>
									
									-- Put the Acc into the ALU first
									alu_src_1L <= DR;
									alu_src_1H <= "00000000";
									
									-- Put the Rn into the ALU
									alu_src_2L <= i_ram_doByte;
									alu_src_2H <= "00000000";
									
									alu_by_wd <= '0';					-- Calculate only 1 byte
								
									-- Set Operation according to the operation type
									case IR(7 DOWNTO 4) is
										when "0010" =>					-- Add without carry
											alu_cy_bw 	<= '0';
											alu_op_code <= ALU_OPC_ADD;
										when "0011" =>					-- Add with carry
											alu_cy_bw 	<= AR(7);
											alu_op_code <= ALU_OPC_ADC;
										when "1001" =>					-- Suub with Borrow
											alu_cy_bw 	<= AR(7);
											alu_op_code <= ALU_OPC_SBB;	
										when "0000" =>						-- Inc target
											alu_cy_bw 	<= '0';
											alu_op_code <= ALU_OPC_INC;
										when "0001" =>						-- Dec target
											alu_cy_bw 	<= '0';
											alu_op_code <= ALU_OPC_DEC;
										when "0101"=>
											alu_op_code<=ALU_OPC_AND;	--And target
										when "0100"=>
											alu_op_code <= ALU_OPC_OR;	--OR target
										when "0110"=>
											alu_op_code <= ALU_OPC_XOR;--XOR target	
										when others =>
											alu_cy_bw 	<= '0';
											alu_op_code <= ALU_OPC_ADD;
									end case;
									-- not implementation for next cycle, because the result & PSW is already on the bus
							when "11011000"|"11011001"|"11011010"|"11011011"|"11011100"|"11011101"|"11011110"|"11011111"|  --DJNZ Rn,rel
							"11010101" --DJNZ direct,rel
							=>
								if(Cycle=Remain_2Cycles) then		--decrement Rn in the first cycle
								-- Put the Acc into the ALU first
									alu_src_1L <= DR;
									alu_src_1H <= "00000000";
									
									-- Put the Rn into the ALU
									alu_src_2L <= i_ram_doByte;
									alu_src_2H <= "00000000";
									alu_by_wd 	<= '1';	
									alu_op_code <= ALU_OPC_DEC;
							elsif(Cycle=Remain_1Cycles) then
							alu_src_1L <= PC(7 downto 0);
							alu_src_1H <=PC(15 downto 8);
							alu_by_wd 	<= '1';
								if( DR/= 0) then 
								if(i_rom_data(7)='0') then
								alu_src_2H<="00000000";
								else
								alu_src_2H<="11111111";
								end if;
								alu_src_2L <=i_rom_data;
								else 
								alu_src_2L <="00000000";
								alu_src_2H<="00000000";
								end if;
							alu_op_code <= ALU_OPC_ADD;
									end if;
							when 	"00100100"|		--  ADD A,#data
									"00110100"|		--  ADDC A,#data
									"10010100"|		--  SUBB A, #data
									"01100100"|		--XRL A,#data
									"01000100"|		--ORL A,#data
									"01010100"		--ANL A,#data
									=>
									
									-- Put the Acc into the ALU first
									alu_src_1L <= DR;
									alu_src_1H <= "00000000";
									
									-- Put the #data into the ALU
									alu_src_2L <= i_rom_data;
									alu_src_2H <= "00000000";
									
									alu_by_wd <= '0';
									
									-- Set Operation according to the operation type
									case IR(7 DOWNTO 4) is
										when "0010" =>					-- Add without carry
											alu_cy_bw 	<= '0';
											alu_op_code <= ALU_OPC_ADD;
										when "0011" =>					-- Add with carry
											alu_cy_bw 	<= AR(7);
											alu_op_code <= ALU_OPC_ADC;
										when "1001" =>					-- Suub with Borrow
											alu_cy_bw 	<= AR(7);
											alu_op_code <= ALU_OPC_SBB;	
										when "0101"=>
											alu_op_code<=ALU_OPC_AND;	--And target
										when "0100"=>
											alu_op_code <= ALU_OPC_OR;	--OR target
										when "0110"=>
											alu_op_code <= ALU_OPC_XOR;--XOR target	
										when others =>
											alu_cy_bw 	<= '0';
											alu_op_code <= ALU_OPC_ADD;
									end case;
								when	 "01010011"|			-- ANL direct,#data
										"01000011"|			--ORL direct,#data
										"01100011" 			--XRL direct,#data
										=>
								if(Cycle = Remain_1Cycles) then
								-- Put the Acc into the ALU first
									alu_src_1L <= DR;
									alu_src_1H <= "00000000";
									
									-- Put the #data into the ALU
									alu_src_2L <= i_rom_data;
									alu_src_2H <= "00000000";
									
									alu_by_wd <= '0';
									
									-- Set Operation according to the operation type
									case IR(7 DOWNTO 4) is
										when "0010" =>					-- Add without carry
											alu_cy_bw 	<= '0';
											alu_op_code <= ALU_OPC_ADD;
										when "0011" =>					-- Add with carry
											alu_cy_bw 	<= AR(7);
											alu_op_code <= ALU_OPC_ADC;
										when "1001" =>					-- Suub with Borrow
											alu_cy_bw 	<= AR(7);
											alu_op_code <= ALU_OPC_SBB;
										when "0101"=>
											alu_op_code<=ALU_OPC_AND;	--And target
										when "0100"=>
											alu_op_code <= ALU_OPC_OR;	--OR target
										when "0110"=>
											alu_op_code <= ALU_OPC_XOR;--XOR target											
										when others =>
											alu_cy_bw 	<= '0';
											alu_op_code <= ALU_OPC_ADD;
											end case;
										end if;
										
							
							when "11110100" --CPL A
							=>
								-- Put the Acc into the ALU first
									alu_src_1L <= DR;
									alu_src_1H <= "00000000";
									
									-- Put the #data into the ALU
									alu_src_2L <= "11111111";
									alu_src_2H <= "00000000";
									alu_op_code <= ALU_OPC_XOR;--XOR target
							
									
							when 	"10010011"	-- MOV A, @(A+DPTR)	
									=>
									if(Cycle= Remain_2Cycles) then
										-- Put the Acc into the ALU first
										alu_src_1L <= DR;
										alu_src_1H <= "00000000";
										
										-- Put the #data into the ALU
										alu_src_2L <= i_ram_doByte;
										alu_src_2H <= AR;
										
										alu_by_wd <= '1';
										alu_cy_bw 	<= '0';
										alu_op_code <= ALU_OPC_ADD;
									else
										DR <= i_rom_data;
										AR <= Acc;
									end if;
									
									
							when	"10000011"	-- MOV A, @(A+PC)
									=>
									if(Cycle= Remain_2Cycles) then
										-- Put the Acc into the ALU first
										alu_src_1L <= DR;
										alu_src_1H <= "00000000";
										
										-- Put the #data into the ALU
										alu_src_2L <= PC(7 downto 0);
										alu_src_2H <= PC(15 downto 8);
										
										alu_by_wd <= '1';
										alu_cy_bw 	<= '0';
										alu_op_code <= ALU_OPC_ADD;
									else
										DR <= i_rom_data;
										AR <= Acc;
									end if;
									
							when "10000010"|			-- ANL C,bit
									"01110010"|			--ORL C,bit
									"10110000"|			--ANL C./bit
									"10100000"			--ORL C,/bit
								=>
			
								if(Cycle= Remain_1Cycles) then
									case IR(1 downto 0) is
									when"10"=>
									-- Put the #data into the ALU
									alu_src_2L <= "1111111"&i_ram_doBit;-- bit from direct address
									when "00"=>
									if(i_ram_doBit='1') then
									alu_src_2L <= "11111110";-- bit from direct address
									else
									alu_src_2L <= "11111111";
									end if;
									when others =>
									end case;
									alu_src_1L <= "0000000"&AR(7);-- PSW
									alu_src_1H <= "00000000";
									alu_src_2H <= "00000000";
									case IR(7 downto 4) is
									when "1000"| "1011"=>
									alu_op_code<= ALU_OPC_AND;
									when "0111"| "1010"=>
									alu_op_code <= ALU_OPC_OR;--XOR target	
									when others =>
									end case;
									end if;
						when	 	"01000000"|  		--JC rel
									"01010000"|			--JNC rel
									"00100000"|			--JB bit,rel
									"00110000"|       --JNB bit,rel
									"00010000"|			--JBC bit rel
									"01110000"|			--JNZ
									"01100000"|			--JZ
									"10000000"|			--SJMP
									"10110101"|			--CJNE A,Direct, rel
									"10110100"|			-- CJNE A,#data,rel
									"10111000" | "10111001" |"10111010" |"10111011"|"10111100"| "10111101"|"10111110"|"10111111"|	 --CJNE Rn,#data,rel
									"10110110" |"10110111"	--CJNE @Rn,#data,rel
								=>
								if(Cycle= Remain_1Cycles) then
								alu_src_1L <= PC(7 downto 0);
								alu_src_1H <=PC(15 downto 8);
								--alu_src_2H<="00000000";
								alu_by_wd 	<= '1';	
								case IR (7 downto 4) is
								when "0100"=>
									if(AR(7)='1') then
									if(DR(7)='0') then
								alu_src_2H<="00000000";
								else
								alu_src_2H<="11111111";
								end if;
									alu_src_2L <=DR;
									else
									alu_src_2L <="00000000";
									alu_src_2H<="00000000";
									end if;
								when "0101"=>
								
								if(AR(7)='0') then
								if(DR(7)='0') then
								alu_src_2H<="00000000";
								else
								alu_src_2H<="11111111";
								end if;
									alu_src_2L <=DR;
									else
									alu_src_2L <="00000000";
									alu_src_2H<="00000000";
									end if;
								when"0010"|"0001"=>
								
									if(i_ram_doBit='1') then
									if(i_rom_data(7)='0') then
								alu_src_2H<="00000000";
								else
								alu_src_2H<="11111111";
								end if;
									alu_src_2L <=i_rom_data;
									else
									alu_src_2L <="00000000";
									alu_src_2H<="00000000";
									end if;
								when "0011"=>
								
								if(i_ram_doBit='0') then
								if(i_rom_data(7)='0') then
								alu_src_2H<="00000000";
								else
								alu_src_2H<="11111111";
								end if;
									alu_src_2L <=i_rom_data;
									else
									alu_src_2L <="00000000";
									alu_src_2H<="00000000";
									end if;
								when "0111" =>
								
								if(AR	/="00000000") then
								if(DR(7)='0') then
								alu_src_2H<="00000000";
								else
								alu_src_2H<="11111111";
								end if;
								alu_src_2L <=DR;
								else
								alu_src_2L <="00000000";
								alu_src_2H<="00000000";
								end if;
								when "0110"=>
								
								if(AR	="00000000") then
								if(DR(7)='0') then
								alu_src_2H<="00000000";
								else
								alu_src_2H<="11111111";
								end if;
								alu_src_2L <=DR;
								else
								alu_src_2L <="00000000";
								alu_src_2H<="00000000";
								end if;
								when "1000"=>
								if(DR(7)='0') then
								alu_src_2H<="00000000";
								else
								alu_src_2H<="11111111";
								end if;
								alu_src_2L <=DR;
								when "1011" =>
								
								if( AR /= DR) then 
								if(i_rom_data(7)='0') then
								alu_src_2H<="00000000";
								else
								alu_src_2H<="11111111";
								end if;
								alu_src_2L <=i_rom_data;
								else 
								alu_src_2L <="00000000";
								alu_src_2H<="00000000";
								end if;
								when others=>
								end case;
								alu_op_code<= ALU_OPC_ADD;
							end if;
							
							when 	"10100011" 		-- INC DPTR
									=>		
									
									if( Cycle = Remain_2Cycles ) then
										-- Put the DPTR into the ALU
										alu_src_1L <= AR;
										alu_src_1H <= i_ram_doByte;
										
										alu_src_2L <= "00000000";
										alu_src_2H <= "00000000";
										
										alu_by_wd <= '1';					-- Calculate 1 word
									
										alu_cy_bw 	<= '0';
										alu_op_code <= ALU_OPC_INC;
									end if;
							when "01110011"  --JMP DPTR
								=>
									if( Cycle = Remain_2Cycles ) then
										-- Put the DPTR into the ALU
										alu_src_1L <= AR;
										alu_src_1H <= i_ram_doByte;
										
										alu_src_2L <= DR;
										alu_src_2H <= "00000000";
										
										alu_by_wd <= '1';					-- Calculate 1 word
									
										alu_cy_bw 	<= '0';
										alu_op_code <= ALU_OPC_ADD;
									end if;
							when 	"10100100"		-- MUL AB	
									=>
									-- Start the multiplication at the first cycle
									if ( Cycle = Remain_4Cycles ) then
										-- Multiply Acc and B
										mul_a_i <= DR;
										mul_b_i <= i_ram_doByte;
									end if;		
									
							when 	"10000100"		-- DIV AB
									=>
									-- Start the multiplication at the first cycle
									if ( Cycle = Remain_4Cycles ) then
										-- Divide Acc with B
										dividend_i <= DR;
										divisor_i <= i_ram_doByte;
										-- Wait for AT LEAST 8 cycle while divisor is preforming division
									end if;
									
							when 	"11010100"		-- DA A
									=>
									if( alu_cy = '1' ) then
										AR(7) <= '1';
									end if;
									
									-- Put the Acc into the ALU first
									alu_src_1L <= alu_ans_L;
									alu_src_1H <= "00000000";
										
									-- Put the +6/+0 into the ALU
									if( alu_ans_L(7 downto 4) > "1001" or AR(7) = '1' or alu_cy = '1' ) then
										alu_src_2L <= "01100000";
										alu_src_2H <= "00000000";
									else
										alu_src_2L <= "00000000";
										alu_src_2H <= "00000000";
									end if;
										
									alu_by_wd <= '0';					-- Calculate only 1 byte
									alu_cy_bw 	<= '0';
									alu_op_code <= ALU_OPC_ADD;
									
							when others
							=>
								-- No defined, just do nothing
						end case;
							--Update to next state
							exe_state <= E0;
							cpu_state <= S6;
					when others =>
						Cycle <= Remain_4Cycles;
						exe_state <= E0;
						cpu_state <= S1;
				end case;
				
			-- Writing State
			-- Write back the Execution result
			when S6=>
				case exe_state is
					when E0=>
						case IR is
							when 	"00101000"| "00101001"| "00101010"| "00101011"| "00101100"| "00101101"| "00101110"| "00101111"|		-- ADD Acc, Rn
									"00111000"| "00111001"| "00111010"| "00111011"| "00111100"| "00111101"| "00111110"| "00111111"|  	-- ADDC Acc, Rn
									"10011000"| "10011001"| "10011010"| "10011011"| "10011100"| "10011101"| "10011110"| "10011111"|  	-- SBBC Acc, Rn
									"01011000" | "01011001" | "01011010" | "01011011" | "01011100" | "01011101" | "01011110" | "01011111"| --ANL Acc,Rn
									"01001000" | "01001001" | "01001010" | "01001011" | "01001100" | "01001101" | "01001110" | "01001111"| --ORL Acc,Rn
									"01101000" | "01101001" | "01101010" | "01101011" | "01101100" | "01101101" | "01101110" | "01101111"| --XOR Acc,Rn
									"00100100"|		--  ADD A,#data
									"00110100"|		--  ADDC A,#data
									"10010100"|		--  SUBB A, #data
									"01100100"|		--XRL A,#data
									"01000100"|		--ORL A,#data
									"01010100"|		--ANL A,#data
									"00100101"|		-- ADD A,direct
									"00110101"|		-- ADDC A,direct
									"10010101"|		-- SUBB A,direct
									"01010101"| 		--ANL A,direct
									"01000101"|			--ORL A,direct
									"01100101"|			--XRL a,direct
									"00100110"|"00100111"|			-- ADD A,@Ri
									"00110110"|"00110111"|			-- ADDC A,@Ri
									"10010110"|"10010111"|			-- SUBB A,@Ri
									"01010110"| "01010111"|		-- ANL A,@Ri
									"01000110" | "01000111"|	--ORL A,@Ri
									"01100110" | "01100111" 	--XRL A,@Ri
									=>
									
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= PSW; 				-- Write flag result back to PSW
									i_ram_diByte <= alu_cy & alu_ac & AR(5 downto 3) & alu_ov & AR(1 downto 0);
									
									AR <= Acc;
							when 	"11001000"|"11001001"|"11001010"|"11001011"|"11001100"|"11001101"|"11001110"|"11001111"|	-- XCH A, Rn
									"11000110"|"11000111"|		-- XCH A, @Ri
									"11000101"						-- XCH A, direct
									=>
									
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= Acc;
									i_ram_diByte <= i_ram_doByte;
									
							when 	"11010110"|	"11010111" -- XCHD A, @Ri 
									=>
									
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= Acc;
									i_ram_diByte <= DR(7 downto 4) & i_ram_doByte(3 downto 0);
									
							when	"00000100"|		-- INC A
									"00010100"|		-- DEC A
									"11100100"|	--CLR A
									"11110100"| --CPL A	
									"00000011"|	--RR A	
									"00100011"| --RL A	
									"11000100"| 	--SWAP A	
									"11100101"|  	-- Mov A,direct
									"01110100"|		--  MOV A,#data
									"11100110"|"11100111"			-- MOV A,@Ri
									=> 
									-- Do nothing but determined the Result address
									AR <= Acc; 
									
							when 	"10010000"	-- MOV DPTR, #data_16
									=>
									if( Cycle=Remain_1Cycles ) then
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
										i_ram_addr <= DPH; 				-- Write flag result back to PSW
										i_ram_diByte <= AR;
									end if;
									
							when "00010011"   --RRC A
							=>
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= PSW; 				-- Write flag result back to PSW
									i_ram_diByte <= DR(0) & AR(6 downto 0);
							when "00110011" --RLC A
							=>
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= PSW; 				-- Write flag result back to PSW
									i_ram_diByte <= DR(7) & AR(6 downto 0);
		
									--AR <= Acc;
							when "11000011"| 	--CLR C
								"11010011"| --set C
								"10110011"--CPL C	
							=>
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= PSW; 				-- Write flag result back to PSW
									case IR(7 downto 4) is
										when "1100" =>					-- Add without carry
											i_ram_diByte <= '0' & AR(6 downto 0);
										when "1101" =>					-- Add with carry
											i_ram_diByte <= '1' & AR(6 downto 0);
										when "1011" =>
											if(AR(7) ='1') then
											i_ram_diByte <= '0' & AR(6 downto 0);
											else
											i_ram_diByte <= '1' & AR(6 downto 0);
											end if;
										when others=>
									end case;										
								
								when "10000010"|			-- ANL C,bit
									"01110010"|		--ORL C,bit
									"10110000"|			--ANL C./bit
									"10100000"			--ORL C,/bit
									=>
									if(Cycle=Remain_1Cycles) then
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= PSW; 				-- Write flag result back to PSw
									i_ram_diByte <= alu_ans_L(0)&AR(6 downto 0);
									end if;
								when "10110101"|			--CJNE A,direct,rel
										"10110100"|			-- CJNE A,#data,rel
										"10111000" | "10111001" |"10111010" |"10111011"|"10111100"| "10111101"|"10111110"|"10111111"|	 --CJNE ACC,Rn,rel
										"10110110" |"10110111"	--CJNE @Rn,#data,rel
										
								=>
									if(Cycle=Remain_2Cycles) then
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= PSW; 				-- Write flag result back to PSw
									i_ram_diByte <= AR(7 downto 0);
									AR <= i_ram_doByte;--backnup Rn or @Rn
									end if;
							when "11000010"|		-- CLR bit
									"11010010"|		-- set bit
									"10110010"|		-- CPL bit
									"00010000"		--JBC bit rel
							=>
								if(Cycle=Remain_1Cycles) then
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '1'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= AR; 				-- Write flag result back to PSW
									case IR(7 downto 4) is
									when "1100" =>
									i_ram_diBit <= '0';
									when "1101"=>
									i_ram_diBit<= '1';
									when "1011"=>
									if((i_ram_doBit)='1') then
									i_ram_diBit <= '0';
									else
									i_ram_diBit<= '1';
									end if;
									when "0001" =>
									if((i_ram_doBit)='1') then
									i_ram_diBit <= '0';
									end if;
									when others=>
									end case;
									end if;	
							when 	"10100100"		-- MUL AB	
									=>
									if( Cycle = Remain_1Cycles ) then
										-- Write LSB answer to Acc first
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';				-- Write new Acc back to Acc
										i_ram_addr <= Acc;
										i_ram_dibyte <= mul_prod_o(7 Downto 0);
									elsif( Cycle = Remain_2Cycles ) then
										-- Prepare PSW state
										AR(7) <= '0';
										
										if ( mul_prod_o(15 downto 8) = "00000000" ) then
											AR(2) <= '0';
										else
											AR(2) <= '1';
										end if;
										
									end if;		
									
							when 	"10000100"		-- DIV AB
									=>
									if( Cycle = Remain_1Cycles ) then
										-- Write LSB answer to Acc first
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';				-- Write quotient back to Acc
										i_ram_addr <= Acc;
										i_ram_dibyte <= quotient_o;
									elsif( Cycle = Remain_4Cycles ) then
										-- Prepare PSW state
										AR(7) <= '0';
										
										if ( i_ram_doByte = "00000000" ) then
											AR(2) <= '1';
										else
											AR(2) <= '0';
										end if;
									end if;
									
							when 	"11010100"		-- DA A
									=>
									
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= PSW; 				-- Write flag result back to PSW
									i_ram_diByte <= (alu_cy or AR(7)) & AR(6 downto 0);
									
									AR <= Acc;							-- Make it pointed to ACC, so that we can share code on S6E2
							
							when 	"00010010"|		-- LCALL
									"00010001"|"00110001"|"01010001"|"01110001"|"10010001"|"10110001"|"11010001"|"11110001"		-- ACALL addr11
									=>
									if( Cycle = Remain_1Cycles ) then
										
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
										
										i_ram_addr <= AR;				-- Write new PC(15-8) to (SP+2)
										i_ram_dibyte <= PC(7 Downto 0);
									end if;
							
							when  "11000000"	-- PUSH	
									=>
									if ( Cycle = Remain_1Cycles ) then
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
										
										i_ram_addr <= SP;				-- Write new SP+1 to SP
										i_ram_dibyte <= AR;
									end if;
							when "11010000" --pop
								=>
								if ( Cycle = Remain_1Cycles ) then
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
										
										i_ram_addr <= SP;				-- Write new SP+1 to SP
										i_ram_dibyte <= DR-1;
									end if;
							when 	"11110110" | "11110111"	--MOV @Ri,A

									=>
--											
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									
									i_ram_addr <= AR;	
									i_ram_diByte <= DR;
							when "10100110"|"10100111" --Mov @Ri, direct
							=>
							if(Cycle = Remain_1Cycles) then
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									
									i_ram_addr <= DR;	
									i_ram_diByte <= i_ram_doByte;
							end if;
							when 	others
									=>
								-- No defined, just do nothing
						end case;
							--Update to next state
							exe_state <= E1;
							cpu_state <= S6;
					when E1=>
						case IR is
							when 	"00101000"| "00101001"| "00101010"| "00101011"| "00101100"| "00101101"| "00101110"| "00101111"|		-- ADD Acc, Rn
									"00111000"| "00111001"| "00111010"| "00111011"| "00111100"| "00111101"| "00111110"| "00111111"|  	-- ADDC Acc, Rn
									"10011000"| "10011001"| "10011010"| "10011011"| "10011100"| "10011101"| "10011110"| "10011111"|  	-- SBBC Acc, Rn
									"01011000" | "01011001" | "01011010" | "01011011" | "01011100" | "01011101" | "01011110" | "01011111"| --ANL Acc,Rn
									"01001000" | "01001001" | "01001010" | "01001011" | "01001100" | "01001101" | "01001110" | "01001111"| --ORL Acc,Rn
									"01101000" | "01101001" | "01101010" | "01101011" | "01101100" | "01101101" | "01101110" | "01101111"| --XOR Acc,Rn
									"00100100"|		--  ADD A,#data
									"00110100"|		--  ADDC A,#data
									"10010100"|		--  SUBB A, #data
									"01100100"|		--XRL A,#data
									"01000100"|		--ORL A,#data
									"01010100"|		--ANL A,#data
									"00100101"|		-- ADD A,direct
									"00110101"|		-- ADDC A,direct
									"10010101"|		-- SUBB A,direct
									"01010101"| 		--ANL A,direct
									"01000101"|			--ORL A,direct
									"01100101"|			--XRL a,direct
									"00100110"|"00100111"|			-- ADD A,@Ri
									"00110110"|"00110111"|			-- ADDC A,@Ri
									"10010110"|"10010111"|			-- SUBB A,@Ri
									"01010110"| "01010111"|		-- ANL A,@Ri
									"01000110" | "01000111"|	--ORL A,@Ri
									"01100110" | "01100111" |	--XRL A,@Ri
									"00000100"|		-- INC A
									"00010100"|		-- DEC A
									"00011000"| "00011001"| "00011010"| "00011011"| "00011100"| "00011101"| "00011110"| "00011111"|		-- DEC Rn
									"00001000"| "00001001"| "00001010"| "00001011"| "00001100"| "00001101"| "00001110"| "00001111"|		-- INC Rn
									"00010101"|		-- DEC direct
									"00000101"|		-- INC direct
									"00010110"|"00010111"|		-- DEC @Ri
									"00000110"|"00000111"|		-- INC @Ri
									"11010100"|		-- DA A
									"01010010"|		--ANL direct,A
									"01000010"|		--ORL direct A
									"01100010"|		--XRL direct A
									"11110100"		--CPL A
									=>
									
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= AR; 				-- Write computed result back to Destination
									i_ram_diByte <= alu_ans_L;
							
							when 	"10010000"	-- MOV DPTR, #data_16
									=>
									if( Cycle=Remain_1Cycles ) then
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
										i_ram_addr <= DPL; 				-- Write flag result back to PSW
										i_ram_diByte <= DR;
									end if;
									
							when "11011000"|"11011001"|"11011010"|"11011011"|"11011100"|"11011101"|"11011110"|"11011111"|  --DJNZ Rn,rel
							"11010101" --DJNZ direct,rel
							=>
								if(Cycle=Remain_2Cycles) then
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= AR; 				-- Write computed result back to Destination
									i_ram_diByte <= alu_ans_L;	
									DR<=alu_ans_L;
								elsif(Cycle=Remain_1Cycles) then
								PC(7 downto 0)<= alu_ans_L;
									PC(15 downto 8)<= alu_ans_H;
								
									end if;
							when "01010011"|			-- ANL direct,#data
									"01000011"|			--ORL direct,#data
									"01100011"			--XRL direct,#data
									=>
									if(Cycle = Remain_1Cycles) then
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= AR; 				-- Write computed result back to Destination
									i_ram_diByte <= alu_ans_L;	
									end if;
							when "11100100"	--CLR A
							=>
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= AR; 				-- Write computed result back to Destination
									i_ram_diByte <= "00000000";
							when "00000011" --RR A
							=>
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= AR; 				-- Write computed result back to Destination
									i_ram_diByte <=DR(0)&DR(7 downto 1);
							when "00100011" --RL A
							=>
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= AR; 				-- Write computed result back to Destination
									i_ram_diByte <=DR(6 downto 0)&DR(7);
							when "00010011"=> --RRC A
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= ACC; 				-- Write computed result back to Destination
									i_ram_diByte <=AR(7)&DR(7 downto 1);
							when "00110011"=> --RLC A
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= ACC; 				-- Write computed result back to Destination
									i_ram_diByte <=DR(6 downto 0)&AR(7);
							when  "11000100" => --SWAP A
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= AR; 				-- Write computed result back to Destination
									i_ram_diByte <=DR(3 downto 0)&DR(7 downto 4);
							when "01000000"|  		--JC rel
									"01010000"|			--JNC rel
									"00100000"|			--JB bit,rel
									"00110000"|       --JNB bit,rel
									"00010000"|			--JBC bit rel
									"01110000"|			--JNZ
									"01100000"|			--JZ
									"10000000"|			--SJMP
									"10110101"|       --CJNE A, direct rel
									"10110100"|			--CJNE A,#data,rel
									"10111000" | "10111001" |"10111010" |"10111011"|"10111100"| "10111101"|"10111110"|"10111111"|	 --CJNE Rn,#data,rel
									"10110110" |"10110111"|	--CJNE @Rn,#data,rel
									 "01110011" --JMP DPTR
									=>
									if(Cycle = Remain_1Cycles ) then
									PC(7 downto 0)<= alu_ans_L;
									PC(15 downto 8)<= alu_ans_H;
									end if;
							when "00000010" 	--LJMP
							=>
							if( Cycle = Remain_1Cycles ) then
							  PC(15 downto 8) <= AR;
							  PC(7 downto 0) <= DR;
							end if;
							when 	"10100011" 		-- INC DPTR
									=>	
									
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									
									if( Cycle = Remain_1Cycles ) then
										i_ram_addr <= DPL;					-- Write new B back to B
										i_ram_dibyte <= alu_ans_L;	
									else
										i_ram_addr <= DPH;					-- Write new PSW back to PSW
										i_ram_dibyte <= alu_ans_H;
									end if;
									
							when 	"10100100"		-- MUL AB	
									=>
									
									if( Cycle = Remain_1Cycles ) then
										-- Write LSB answer to Acc first	
									
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
									
										i_ram_addr <= B;					-- Write new B back to B
										i_ram_dibyte <= mul_prod_o(15 Downto 8);	
									elsif( Cycle = Remain_2Cycles ) then
									
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
									
										i_ram_addr <= PSW;				-- Write new PSW back to PSW
										i_ram_dibyte <= AR;
									end if;
							
							when 	"11001000"|"11001001"|"11001010"|"11001011"|"11001100"|"11001101"|"11001110"|"11001111"|	-- XCH A, Rn
									"11000110"|"11000111"|		-- XCH A, @Ri
									"11000101"						-- XCH A, direct
									=>
									
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= AR;
									i_ram_diByte <= DR;
									
							when 	"11010110"|	"11010111" -- XCHD A, @Ri 
									=>
									
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= AR;
									i_ram_diByte <= i_ram_doByte(7 downto 4) & DR(3 downto 0);
									
							when 	"10000100"		-- DIV AB
									=> 
									
									if( Cycle = Remain_1Cycles ) then
										-- Write LSB answer to Acc first	
									
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
									
										i_ram_addr <= B;					-- Write remainder back to B
										i_ram_dibyte <= remainder_o;	
									elsif( Cycle = Remain_4Cycles ) then
									
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
									
										i_ram_addr <= PSW;				-- Write new PSW back to PSW
										i_ram_dibyte <= AR;
									end if;
							
							when 	"00010010"|		-- LCALL
									"00010001"|"00110001"|"01010001"|"01110001"|"10010001"|"10110001"|"11010001"|"11110001"		-- ACALL addr11
									=>
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									if( Cycle = Remain_2Cycles ) then
										-- Store SP+2 first
									
										i_ram_addr <= SP;				-- Write new SP+2 to SP
										i_ram_dibyte <= AR + 1;
									else
										
										i_ram_addr <= AR + 1;				-- Write new PC(15-8) to (SP+2)
										i_ram_dibyte <= PC(15 Downto 8);
									
										if( IR = "00010010" ) then
											if( int_fetch = '1' ) then
												-- If this is hardware genereted LCALL
												int_fetch <= '0';
												
												case curr_int(2 downto 0) is
													when SERIAL_INTERRUPT		=>
														PC <= x"0023";
													when TIMER_1_INTERRUPT		=>
														PC <= x"001B";
													when EXTERNAL_1_INTERRUPT	=>
														PC <= x"0013";
													when TIMER_0_INTERRUPT		=>
														PC <= x"000B";
													when EXTERNAL_0_INTERRUPT	=>
														PC <= x"0003";													
													when others =>
														PC <= DR & i_rom_data;
												end case;
												
												-- reset the interrupt and force the RAM to accept the new TCON
												erase_flag <= '1';	
											else
												PC <= DR & i_rom_data;
											end if;
										else
											PC <= PC(15 Downto 11) & IR(7 Downto 5) & DR;
										end if;
									end if;
							when "00000001"|"00100001"|"01000001"|"01100001"|"10000001"|"10100001"|"11000001"|"11100001"		-- AJMP addr11
									=> 
									if( Cycle = Remain_1Cycles ) then
											PC <= PC(15 Downto 11) & IR(7 Downto 5) & DR;
									end if;
							when	"00110010"		-- RETI
									=>
									if ( Cycle = Remain_1Cycles ) then
										PC(7 downto 0) <= i_ram_doByte;
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
										
										i_ram_addr <= SP;				-- Write new SP-2 to SP
										i_ram_dibyte <= AR - 1;
										
										-- Reset Serving_int so that same level interrupt can be accept after that.
										curr_int <= (Others=>'0');
									end if;
							when	"00100010"		-- RET
									=>
									if ( Cycle = Remain_1Cycles ) then
										PC(7 downto 0) <= i_ram_doByte;
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
										
										i_ram_addr <= SP;				-- Write new SP-2 to SP
										i_ram_dibyte <= AR - 1;
									end if;
							when 	"10000110" | "10000111"|	-- MOV Direct, @Ri
									"10001000"|"10001001"|"10001010"|"10001011"|"10001100"|"10001101"|"10001110"|"10001111"| --Mov direct,Rn
									"01111000" |"01111001" |"01111010" |"01111011" |"01111100" |"01111101" |"01111110" |"01111111"| --MOV Rn,#data 
									"10101000" | "10101001" | "10101010" | "10101011" | "10101100" | "10101101" | "10101110" |"10101111"| -- Mov Rn,direct
									"01110101" | -- MOV direct,#dat
									"11100101"|  	-- Mov A,direct
									"11101000"|"11101001"|"11101010"|"11101011"|"11101100"|"11101101"|"11101110"|"11101111"|		-- Mov A, Rn
									"11111000" | "11111001" | "11111010" | "11111011" | "11111100" | "11111101" | "11111110" | "11111111"| --Mov Rn,A
									"11100110"|"11100111"|			-- MOV A,@Ri
									"11110101" |			--Mov direct,A
									"01110110" | "01110111" |  --MOV @Ri,#data
									"10000101"|  -- MOV direct,direct 
									"11000000"|	-- PUSH
									"10010011"|	-- MOV A, @(A+DPTR)
									"10000011"	-- MOV A, @(A+PC)
									=> 
									if( Cycle = Remain_1Cycles ) then


										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
										
										i_ram_addr <= AR;				-- Write new SP-2 to SP
										i_ram_dibyte <= DR;
									end if;
							when "11010000" --POP
								=>
								if( Cycle = Remain_1Cycles ) then
										i_ram_wrByte <= '1'; 
										i_ram_rdByte <= '0'; 
										i_ram_wrBit <= '0'; 
										i_ram_rdBit <= '0';
										
										i_ram_addr <= AR;				-- Write new SP-2 to SP
										i_ram_dibyte <= i_ram_dobyte;
									end if;
							when 	"01110100"		--  MOV A,#data
									=>
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';
									i_ram_addr <= AR; 				-- Write computed result back to Destination
									i_ram_diByte <= i_rom_data;
									
							 when	"10100010" --MOV c,bit
									=>
									i_ram_wrByte <= '1'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '0'; 
									i_ram_rdBit <= '0';				-- Write new DPL back to Acc
									i_ram_addr <= PSW;
									i_ram_dibyte <= i_ram_dobit & AR(6 downto 0);
									
							when "10010010"		--MOV bit,c
									=>
									i_ram_wrByte <= '0'; 
									i_ram_rdByte <= '0'; 
									i_ram_wrBit <= '1'; 
									i_ram_rdBit <= '0';				-- Write new DPL back to Acc
									i_ram_addr <= i_rom_data;
									i_ram_diBit <= AR(7);
							when others
							=>
								-- No defined, just do nothing
						end case;

							--Update to next state
							Cycle <= Cycle + 1;
							exe_state <= E0;
							cpu_state <= S1;
					when others =>
						Cycle <= Remain_4Cycles;
						exe_state <= E0;
						cpu_state <= S1;
				end case;
			
			when others => 
				Cycle <= Remain_4Cycles;
				exe_state <= E0;
				cpu_state <= S1;
			end case; --cpu_state
end if;
end process;
end seq_arch;

-------------------------------------------------------------------------------

-- end of file --
